package com.stdz.counter.core.thread;

import com.stdz.counter.core.cache.MeterFlagCache;
import com.stdz.counter.core.cache.MeterInfoCache;
import com.stdz.counter.core.cache.MeterInfoTempCache;
import com.stdz.counter.core.constant.DataMode;
import com.stdz.counter.core.constant.MeterModel;
import com.stdz.counter.core.pool.ClientPool;
import com.stdz.counter.dao.*;
import com.stdz.counter.entity.MeterInfo;
import com.stdz.counter.entity.MeterRecord;
import com.stdz.counter.utils.ModbusHelper;
import com.stdz.counter.utils.ResourceUtil;
import de.re.easymodbus.modbusclient.ModbusClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 *
 */
public class SyncDataThread implements Runnable {

    private static transient Logger logger = LoggerFactory.getLogger(SyncDataThread.class);

    @Resource
    private MeterInfoDao meterInfoDao;
    @Resource
    private MeterRecordDao meterRecordDao;
    @Resource
    private MeterHDao meterHDao;
    @Resource
    private MeterDDao meterDDao;
    @Resource
    private MeterMDao meterMDao;
    @Resource
    private MeterYDao meterYDao;

    private String comPort;

    private List<MeterInfo> meterInfos;

    public SyncDataThread(String comPort, List<MeterInfo> meterInfos) {
        ResourceUtil.autowired(this);
        this.comPort = comPort;
        this.meterInfos = meterInfos;
    }

    @Override
    public void run() {
        logger.info("config refresh thread run start");
        if (this.meterInfos == null || meterInfos.size() == 0) {
            return;
        }
        ModbusClient modbusClient = ClientPool.getInstance().createModbusClient(comPort);
        if (modbusClient == null) {
            return;
        }
        if (modbusClient.isConnected()) {
            logger.info("modbus connect success");
        }
        try {
            this.sync(modbusClient);
        } catch (Throwable t) {
            logger.error("sync data exception:", t);
        } finally {
            ClientPool.getInstance().releaseModbusClient(comPort, modbusClient);
        }
        logger.info("config refresh thread run end");
    }

    private void sync(ModbusClient modbusClient) {
        for (MeterInfo meterInfo : meterInfos) {
            try {
                this.syncMeterInfo(modbusClient, meterInfo);
            } catch (Throwable t) {
                logger.error("syncMeterInfo exception:", t);
            }
        }
    }

    private void syncMeterInfo(ModbusClient modbusClient, MeterInfo meterInfo) {
        MeterModel meterModel = MeterModel.getMeterModel(meterInfo.getMeterModel());
        if (meterModel == null) {
            logger.error("not config meter info right model");
            return;
        }
        DataMode dataMode = DataMode.getDataMode(meterInfo.getDataMode());
        if (dataMode == null) {
            return;
        }
        modbusClient.setUnitIdentifier(meterInfo.getModbusDeviceId());
        int upperRowVal = 0;
        int lowerRowVal = 0;
        int decimalDigit = 0;
        int alarm1 = -1;
        int alarm2 = -1;
        int scaleRate = 0;
        int upperRowPos= meterModel.getDataPos(dataMode.getMode());
        if (upperRowPos > 0) {
            upperRowVal = ModbusHelper.readUpperRowData(modbusClient, meterModel, meterInfo);
            lowerRowVal = ModbusHelper.readLowerRowData(modbusClient, meterModel, meterInfo);
            logger.info("com:{} meterDevice:{}, up:{}, low:{}",
                    new Object[]{comPort, meterInfo.getModbusDeviceId(), upperRowVal, lowerRowVal});
        }
        MeterInfo tempMeterInfo = MeterInfoTempCache.getInstance().getMeterInfo(meterInfo.getMeterId());
        int online = 0;
        if (tempMeterInfo != null) {
            decimalDigit = tempMeterInfo.getDecimalDigit();
            alarm1 = Integer.parseInt(tempMeterInfo.getAlarm1());
            alarm2 = Integer.parseInt(tempMeterInfo.getAlarm2());
//            scaleRate = tempMeterInfo.getScaleRate();
            int scaleRatePos = meterModel.getScalePos();
            if (scaleRatePos > 0) {
                scaleRate = ModbusHelper.readScaleRate(modbusClient, meterModel);
                if (meterModel == MeterModel.CR76 && scaleRate > 0) {
                    //
                } else if (meterModel == MeterModel.ST76 && scaleRate > 0) {
                    // 实际倍数需要除以100000（10w）,此处不做处理，界面上再处理
                }
            }
            if ((upperRowVal > 0 && lowerRowVal > 0) || scaleRate > 0) {
                online = 1;
            }
        } else {
            int decimalDigitPos = meterModel.getDecimalDigitPos();
            if (decimalDigitPos > 0) {
                int[] deimalDigitDatas = ModbusHelper.readData(modbusClient, decimalDigitPos, 1);
                if (deimalDigitDatas.length > 0) {
                    logger.info("deimalDigitDatas:{},{}", new Object[]{deimalDigitDatas[0], 1});
                }
                if (deimalDigitDatas != null && deimalDigitDatas.length > 0) {
                    decimalDigit = deimalDigitDatas[0] & 0xf;
                }

            }
            int alarm1Pos = meterModel.getAlarm1Pos();
            if (alarm1Pos > 0) {
                alarm1 = ModbusHelper.readAlarm1(modbusClient, meterModel);
            }
            int alarm2Pos = meterModel.getAlarm2Pos();
            if (alarm2Pos > 0) {
                alarm2 = ModbusHelper.readAlarm2(modbusClient, meterModel);
            }
            int scaleRatePos = meterModel.getScalePos();
            if (scaleRatePos > 0) {
                scaleRate = ModbusHelper.readScaleRate(modbusClient, meterModel);
                if (meterModel == MeterModel.CR76 && scaleRate > 0) {
                    //
                } else if (meterModel == MeterModel.ST76 && scaleRate > 0) {
                    // 实际倍数需要除以100000（10w）,此处不做处理，界面上再处理
                }
            }
            logger.info("com:{} meterDevice:{}, up:{}, low:{}, decimalDigit:{}, scale:{}, al1:{}, al2:{}",
                    new Object[]{comPort, meterInfo.getModbusDeviceId(), upperRowVal,
                            lowerRowVal, decimalDigit, scaleRate, alarm1, alarm2});
            if (upperRowVal > 0 || lowerRowVal > 0 || scaleRate > 0
                    || alarm1 > 0 || alarm2 > 0 || decimalDigit > 0) {
                online = 1;
            }
        }
        MeterFlagCache.setMeterFlag(meterInfo.getMeterId(), online);
        meterInfo.setAlarm1(String.valueOf(alarm1));
        meterInfo.setAlarm2(String.valueOf(alarm2));
        meterInfo.setScaleRate(scaleRate);
        meterInfo.setDecimalDigit(decimalDigit);
        meterInfo.setUpperRowVal(upperRowVal);
        meterInfo.setLowerRowVal(lowerRowVal);
        meterInfo.setOnline(online);
        if (meterInfo.getDisplayUpperRowVal().length() > 7) {
            logger.error("wrong val:", meterInfo.getDisplayUpperRowVal());
            return;
        }
        if (tempMeterInfo == null && online == 1) {
            MeterInfoTempCache.getInstance().cacheComMeterInfos(meterInfo.getMeterId(), meterInfo);
        }
        this.syncDB(meterInfo);
    }

    private void syncDB(MeterInfo meterInfo) {
        try {
            int update = meterInfoDao.syncMeterData(meterInfo);
            if (update == 0) {
                logger.error("sync meter:{} data to db fail", new Object[]{meterInfo.getMeterId()});
            }
        } catch (Throwable t) {
            logger.error("sync meter data to db exception", t);
        }
        this.recordLog(meterInfo);
    }

    private void recordLog(MeterInfo meterInfo) {
        MeterRecord meterRecord = new MeterRecord();
        meterRecord.setCreateTime(new Date());
        meterRecord.setName(meterInfo.getMeterName());
        meterRecord.setMeterId(meterInfo.getMeterId());
        meterRecord.setUpperRow(meterInfo.getDisplayUpperRowVal());
        try {
            meterRecordDao.addMeterRecord(meterRecord);
        } catch (Throwable t) {
            logger.error("inject meter record exception:", t);
        }
        this.handleMinuteRecord(meterRecord);
        this.handleHourRecord(meterRecord);
        this.handleDayRecord(meterRecord);
        this.handleMonthRecord(meterRecord);

    }

    private void handleHourRecord(MeterRecord meterRecord) {
        MeterRecord tempMeterRecord = meterHDao.queryMeterH(meterRecord.getMeterId(), meterRecord.getCreateTime());
        if (tempMeterRecord == null) {
            meterHDao.addMeterH(meterRecord);
        } else {
            meterHDao.updateMeterH(tempMeterRecord.getId(), meterRecord.getUpperRow());
        }
    }

    private void handleDayRecord(MeterRecord meterRecord) {
        MeterRecord tempMeterRecord = meterDDao.queryMeterD(meterRecord.getMeterId(), meterRecord.getCreateTime());
        if (tempMeterRecord == null) {
            meterDDao.addMeterD(meterRecord);
        } else {
            meterDDao.updateMeterD(tempMeterRecord.getId(), meterRecord.getUpperRow());
        }
    }

    private void handleMinuteRecord(MeterRecord meterRecord) {
        MeterRecord tempMeterRecord = meterMDao.queryMeterM(meterRecord.getMeterId(), meterRecord.getCreateTime());
        if (tempMeterRecord == null) {
            meterMDao.addMeterM(meterRecord);
        } else {
            meterMDao.updateMeterM(tempMeterRecord.getId(), meterRecord.getUpperRow());
        }
    }

    private void handleMonthRecord(MeterRecord meterRecord) {
        MeterRecord tempMeterRecord = meterYDao.queryMeterY(meterRecord.getMeterId(), meterRecord.getCreateTime());
        if (tempMeterRecord == null) {
            meterYDao.addMeterY(meterRecord);
        } else {
            meterYDao.updateMeterY(tempMeterRecord.getId(), meterRecord.getUpperRow());
        }
    }

    public static void main(String[] args) {
        byte bt = 64;
        System.out.println(Integer.toBinaryString(48232));
        System.out.println(Integer.toBinaryString(-17304));
        System.out.println();
    }
}
